package smartcase.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import smartcase.base.*;
import smartcase.base.file.FileStruct;
import smartcase.base.log.Log;
import smartcase.base.log.LogStruct;
import smartcase.common.constants.ProjectConstants;
import smartcase.common.util.JsonUtil;
import smartcase.config.log.LogStructConsumer;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.File;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;

import static smartcase.base.ApplicationContextProviderKt.getBean;
import static smartcase.base.log.LogFactory.getLog;

@WebListener
@Component
public class ConfigurationDefineImpl
    implements ConfigurationDefine, CommandLineRunner, ServletContextListener {

  private String configFilePath;
  private final ScheduledExecutorService reloadConfigExecutor = Executors.newScheduledThreadPool(1);
  private final Log log = getLog(ConfigurationDefineImpl.class);
  private ObjectMapper mapper = new ObjectMapper();
  private HotLoadConfiguration hotLoadConfiguration;
  private boolean containerStarted = false;

  @Override
  public void contextInitialized(ServletContextEvent sce) {
    this.containerStarted = true;
  }

  @Override
  public String getModule() {
    return ProjectConstants.MODULE_NAME;
  }

  @Override
  public Consumer<LogStruct> getLogConsumer() {
    return logStruct -> {
      if (containerStarted) {
        LogStructConsumer logStructConsumer = getBean(LogStructConsumer.class);
        logStructConsumer.reportLog2Cls(logStruct);
      }
    };
  }

  @Override
  public Supplier<Type> getApiResponseType() {
    return () -> ApiResponse.class;
  }

  @Override
  public Supplier<Object> createApiResponse() {
    return StandardKt::ok;
  }

  @Override
  public Function<FileStruct, Boolean> getFileUploader() {
    return fileStruct -> true;
  }

  @Override
  public HotLoadConfiguration getHotLoadConfiguration() {
    return this.hotLoadConfiguration;
  }

  @Override
  public Consumer<LogStruct> alarm() {
    return logStruct -> {
      LogStructConsumer logStructConsumer = getBean(LogStructConsumer.class);
      if (logStructConsumer != null) {
        logStructConsumer.reportLog2Cls(logStruct);
      }
    };
  }

  @Override
  public String getConfigFilePath() {
    return configFilePath;
  }

  @Override
  public ReloadConfigEnum getReloadConfigEnum() {
    return ReloadConfigEnum.LOCAL;
  }

  /** -hotConfigFilePath */
  @Override
  public void run(String... args) throws Exception {
    if (this.getReloadConfigEnum() == null)
      throw new RuntimeException("reload config enum must be config");
//    if (this.getReloadConfigEnum() == ReloadConfigEnum.LOCAL) {
//      Pattern pattern = Pattern.compile("^-HconfigFilePath=(.*)$");
//      this.configFilePath =
//          Arrays.stream(args)
//              .map(pattern::matcher)
//              .filter(t -> t.find() && t.groupCount() == 1)
//              .map(t -> t.group(1))
//              .findFirst()
//              .orElseThrow(() -> new RuntimeException("hotConfigFilePath require"));
//
//      File file;
//      if (!(file = new File(configFilePath)).exists()) {
//        log.error("{} local file path not exist", configFilePath);
//        throw new RuntimeException("config file error");
//      }
//      if (file.isDirectory()) {
//        log.error("{} local file is directory", configFilePath);
//        throw new RuntimeException("local file is directory");
//      }
//
//      reloadConfigExecutor.scheduleAtFixedRate(
//          new Runnable() {
//            @SneakyThrows
//            @Override
//            public void run() {
//              ConfigurationDefineImpl.this.hotLoadConfiguration =
//                  (HotLoadConfiguration) mapper.readValue(file, HotLoadConfigurationImpl.class);
//
//              log.info("reload configuration value succ {}", JsonUtil.toJsonString(hotLoadConfiguration));
//            }
//          },
//          0,
//          3,
//          TimeUnit.SECONDS);
//    }
  }
}
